import { _decorator, Component, instantiate, Node, Prefab, resources, Texture2D, Vec3, Vec2, director } from 'cc';
const { ccclass, property } = _decorator;

import { Block } from './Block';
import { AudioManager } from './AudioManager';
@ccclass('Game')
export class Game extends Component {
    @property({ type: Prefab })
    private blockPrefab: Prefab = null!; // 拼图块的预制体
    @property({ type: Node })
    private bgNode: Node = null!; // 背景节点

    @property({ type: AudioManager })
    private audioManager: AudioManager = null!; // 绑定音频节点

    private blockNum: number = 3; // 拼图数量

    private picNodeArr = []; // 图片节点数组

    private hideBlockNode: Node;

    start() {
        this.loadPicture();
        // 全局事件 监听拼图块点击的回调
        director.on('click_pic', this.onClickPic, this);
    }

    update(deltaTime: number) {}

    // 动态加载图片资源
    loadPicture() {
        const path = 'pic_1/texture';
        resources.load(path, Texture2D, (err, texture) => {
            if (err) {
                console.log(err);
                return;
            }

            // 资源加载成功，初始化游戏
            this.initGame(texture);
            this.removeOnePic();
            this.randomPic();
        });
    }

    // 初始化游戏
    initGame(texture: Texture2D) {
        this.picNodeArr = [];

        // 计算拼图块的边宽
        let blockSide = texture.image.width / this.blockNum;

        // 生成N*N的拼图块，N为blockNum - 分别将block预制体及背景节点进行绑定

        for (let i = 0; i < this.blockNum; i++) {
            this.picNodeArr[i] = [];

            for (let j = 0; j < this.blockNum; j++) {
                const blockNode = instantiate(this.blockPrefab); // 实例化拼图块block预制体
                const blockScript = blockNode.getComponent('Block') as Block; // 获取预制体上的脚本组件Block

                // 为拼图块节点设定位置
                blockNode.setPosition(new Vec3(j * blockSide, -i * blockSide, 0));

                // 初始化拼图块 - 绑定拼图的贴图纹理
                const coord = new Vec2(j, i); // 坐标
                blockScript.initBlock(texture, blockSide, coord);

                // 设定拼图节点数组 - 二维数组
                this.picNodeArr[i][j] = blockNode;

                // 将拼图块加入到背景节点下
                this.bgNode.addChild(blockNode);
            }
        }
    }

    // 去掉一个的拼图块的空间，因为拼图需要一个可以移动的空间
    // 这里去掉右下角的拼图块，根据拼图数量-1，可得到最右边，最下边的拼图
    removeOnePic() {
        let pos = new Vec2(this.blockNum - 1, this.blockNum - 1); // 二维向量

        let picNode = this.picNodeArr[pos.y][pos.x]; // 找到需要去掉的拼图节点
        picNode.active = false; // 关闭拼图的激活属性
        this.hideBlockNode = picNode; // 存储隐藏的图片节点
    }

    // 打乱拼图顺序
    randomPic() {
        let randomTime: number = 100; // 随机次数

        for (let i = 0; i < randomTime; i++) {
            // 定义方向数组
            let directions = [new Vec2(0, 1), new Vec2(0, -1), new Vec2(1, 0), new Vec2(-1, 0)];
            // 随机选择一个方向（上、下、左、右）来确定要交换的拼图块的位置
            let randomDirection = directions[Math.floor(Math.random() * directions.length)];
            let hideBlockNodeScript = this.hideBlockNode.getComponent('Block') as Block;
            let nearIndex = hideBlockNodeScript.nowIndex.clone().add(randomDirection);

            // 越界检测 - 进行边界检测，确保交换后的位置在有效范围内
            if (nearIndex.x < 0 || nearIndex.x >= this.blockNum || nearIndex.y < 0 || nearIndex.y >= this.blockNum) {
                continue;
            }
// 交换两个位置的拼图块
            this.swapPicByPos(hideBlockNodeScript.nowIndex, nearIndex);
        }
    }

    // 交换两个位置的拼图块 - 根据传入的当前位置nowPos和目标位置desPos，获取对应位置的拼图块节点
    swapPicByPos(nowPos: Vec2, desPos: Vec2) {
        let nowPicNode = this.picNodeArr[nowPos.y][nowPos.x];
        let desPicNode = this.picNodeArr[desPos.y][desPos.x];

        // 交换位置 - 实现拼图块的移动效果
        let tempPos = nowPicNode.position.clone();
        nowPicNode.position = desPicNode.position;
        desPicNode.position = tempPos;

        // 交互标记
        let nowPicNodeScript = nowPicNode.getComponent('Block') as Block;
        let desPicNodeScript = desPicNode.getComponent('Block') as Block;
        let tempIndex = nowPicNodeScript.nowIndex.clone();
        nowPicNodeScript.nowIndex = desPicNodeScript.nowIndex;
        desPicNodeScript.nowIndex = tempIndex;

        // 交换数组标记位置 - 交换它们在拼图块数组中的位置
        let tempNode = nowPicNode;
        this.picNodeArr[nowPos.y][nowPos.x] = desPicNode;
        this.picNodeArr[desPos.y][desPos.x] = tempNode;
    }

    // 点击处理
    onClickPic(nowIndex) {
        let directions = [new Vec2(0, 1), new Vec2(0, -1), new Vec2(1, 0), new Vec2(-1, 0)];
        let nearBlockNode;

        // 检查上下左右是否有位置可以移动
        for (let dir of directions) {
            let nearIndex = nowIndex.clone().add(dir);

            // 越界检测
            if (nearIndex.x < 0 || nearIndex.x >= this.blockNum || nearIndex.y < 0 || nearIndex.y >= this.blockNum) {
                continue;
            }

            let blockNode = this.picNodeArr[nearIndex.y][nearIndex.x];
            if (!blockNode || blockNode.active) continue;

            nearBlockNode = blockNode;
        }

        // 如果存在合法位置，当前位置与空位交互
        if (nearBlockNode) {
            let nearBlockNodeScript = nearBlockNode.getComponent('Block') as Block;
            this.swapPicByPos(nowIndex, nearBlockNodeScript.nowIndex);
            this.completeCheck();
        }

        // 音效
        this.audioManager.playSound();
    }

    // 完成检测
    completeCheck() {
        let cnt = 0;
        for (let i = 0; i < this.blockNum; i++) {
            for (let j = 0; j < this.blockNum; j++) {
                const blockNode = this.picNodeArr[i][j];
                const blockNodeScript = blockNode.getComponent('Block') as Block;

                if (blockNodeScript.nowIndex.equals(blockNodeScript.startIndex)) {
                    cnt++;
                }
            }
        }

        // 拼图是否全部归位
        if (cnt == this.blockNum * this.blockNum) {
            this.hideBlockNode.active = true;
            console.log('游戏结束');
        }
    }
}
